<?php
require_once (__DIR__.'/wxBizMsgCrypt.php');
require_once (dirname(__DIR__).'/core/CreateUuid.php');

class Auth {
	const API_URL_PREFIX = 'https://api.weixin.qq.com/cgi-bin';
	const API_COMPONENT_TOKEN_URL = '/component/api_component_token';
	const API_CREATE_PREAUTHCODE_URL = '/component/api_create_preauthcode?component_access_token=';
	const API_QUERY_AUTH_URL = '/component/api_query_auth?component_access_token=';
	const API_AUTHORIZER_TOKEN_URL = '/component/api_authorizer_token?component_access_token=';
	const API_GET_AUTHORIZER_INFO_URL = '/component/api_get_authorizer_info?component_access_token=';
	const API_GET_AUTHORIZER_OPTION_URL = '/component/api_get_authorizer_option?component_access_token=';
	const API_SET_AUTHORIZER_OPTION_URL = '/component/api_set_authorizer_option?component_access_token=';
	const API_REDIRECT = 'https://mp.weixin.qq.com/cgi-bin/componentloginpage?';
	const USER_GET_URL='/user/get?';
	private $appid;
	private $options;
	private $appsecret;
	private $component_verify_ticket;
	private $_funcflag = false;
	public $debug = true;
	public $errCode = 40001;
	public $errMsg = "no access";
	private $pre_auth_code;
	private $component_access_token;
	private $authorizer_access_token;
	private $next_openid;
	public function __construct($options) {
		$this -> options = $options;
		$this -> appid = isset($options['component_appid']) ? $options['component_appid'] : '';
		$this -> appsecret = isset($options['component_appsecret']) ? $options['component_appsecret'] : '';
		$this -> component_verify_ticket = isset($options['component_verify_ticket']) ? $options['component_verify_ticket'] : '';
	}

	//测试函数
	/*
	 * 微信对话框模块出故障时，可以将调试信息写入文件，从而分析问题
	 * 对应写入信息页面，还应该有一个可查询文件的页面，目前我都是直接在服务器上看文件的
	 *
	 */
	public function debug_info_write($info) {
		$filename = './a.txt';
		$fp = fopen($filename, 'w+');
		fwrite($fp, $info . "\n");
		fclose($fp);
	}

	/**
	 * 读取调试页面
	 */
	public function debug_info_read() {
		header("Content-Type: text/html; charset=utf-8");
		$filename = './a.txt';
		$fp = fopen($filename, "r");
		$contents = fread($fp, filesize($filename));
		fclose($fp);
		dump($contents);
	}

	public static function xmlSafeStr($str) {
		return '<![CDATA[' . preg_replace("/[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]/", '', $str) . ']]>';
	}

	/**
	 * 数据XML编码
	 * @param mixed $data 数据
	 * @return string
	 */
	public static function data_to_xml($data) {
		$xml = '';
		foreach ($data as $key => $val) {
			is_numeric($key) && $key = "item id=\"$key\"";
			$xml .= "<$key>";
			$xml .= (is_array($val) || is_object($val)) ? self::data_to_xml($val) : self::xmlSafeStr($val);
			list($key, ) = explode(' ', $key);
			$xml .= "</$key>";
		}
		return $xml;
	}

    /** xml转换成json */
    public static function xmlToArray($xml)
    {
        if (!$xml)
            return false;

        //禁止引用外部xml
        libxml_disable_entity_loader(true);
        //使用SimpleXMLElement转换json成字符串
        $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $data;
    }
    public static function checkAuth()
    {
        $encodingAesKey = Yii::$app->params['wechat']['encodingAesKey'];
        $token = Yii::$app->params['wechat']['token'];
        $appId = Yii::$app->params['wechat']['appid'];

        $timeStamp  = empty($_GET['timestamp'])     ? ""    : trim($_GET['timestamp']) ;
        $nonce      = empty($_GET['nonce'])     ? ""    : trim($_GET['nonce']) ;
        $signature      = empty($_GET['signature'])     ? ""    : trim($_GET['signature']) ;

        $arr = [
            'timestamp'=>$timeStamp,
            'nonce'=>$nonce,
            'token'=>$token,
        ];
        ksort($arr);

        $msg = sha1(implode($arr));
        YII_DEBUG && self::logResult("/crypt.log",'加密的字符串：'.$msg.'获取的到的字符串：'.$signature);

    }

    /**
     * 解密消息
     * @param string $xml
     * @return bool|mixed
     */
    public static function cryptXmlToArray($file='result',$xml = '' )
    {
        $encodingAesKey = Yii::$app->params['wechat']['encodingAesKey'];
        $token = Yii::$app->params['wechat']['token'];
        $appId = Yii::$app->params['wechat']['appid'];

        if (!$xml)
            $xml = file_get_contents("php://input");

        $timeStamp  = empty($_GET['timestamp'])     ? ""    : trim($_GET['timestamp']) ;
        $nonce      = empty($_GET['nonce'])     ? ""    : trim($_GET['nonce']) ;
        $msg_sign   = empty($_GET['msg_signature']) ? ""    : trim($_GET['msg_signature']) ;
        $encryptMsg = file_get_contents('php://input');
        $pc = new \WXBizMsgCrypt($token, $encodingAesKey, $appId);

        $xml_tree = new \DOMDocument();
        $xml_tree->loadXML($encryptMsg);
        $array_e = $xml_tree->getElementsByTagName('Encrypt');
        $encrypt = $array_e->item(0)->nodeValue;

        $format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%s]]></Encrypt></xml>";
        $from_xml = sprintf($format, $encrypt);

        // 第三方收到公众号平台发送的消息
        $msg = '';
        $errCode = $pc->decryptMsg($msg_sign, $timeStamp, $nonce, $from_xml, $msg);

        if ($errCode == 0) {
            YII_DEBUG && self::logResult("/{$file}.log",'解密后文件：'.$msg);

            return self::xmlToArray($msg);
        } else {
            YII_DEBUG && self::logResult('/error.log','解密后失败：'.$errCode);
            return false;
            //print($errCode . "\n");
        }
    }

    /**加密消息体
     * @param $data
     * @param bool $json
     * @return bool|string
     */
    public function cryptArrayToXml($data, $json = false)
    {

        $encodingAesKey = Yii::$app->params['wechat']['encodingAesKey'];
        $token = Yii::$app->params['wechat']['token'];
        $appId = Yii::$app->params['wechat']['appid'];
        if (!$data) return false;

        if (is_array($data)) {
            if ($json) {
                return json_encode($data);
            }
            $data = self::arrayToXml($data);
        }
        $timestamp = time();
        $nonce = self::makeNonceStr();

        $pc = new WXBizMsgCrypt($token, $encodingAesKey, $appId);
        $encryptMsg = '';

        $errCode = $pc->encryptMsg($data, $timestamp, $nonce, $encryptMsg);
        if ($errCode == 0) {
            return $encryptMsg;
        }

        return false;
    }

    /**
     * 生成制定长度随机数
     * @param  integer $len [指定长度]
     * @return [randChars]       [随机字符串]
     */
    private function makeNonceStr($len = 32)
    {
        $chars = [
            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
            "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
            "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G",
            "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
            "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",
            "3", "4", "5", "6", "7", "8", "9"
        ];

        $charsLen = count($chars)-1;
        //打乱数组
        shuffle($chars);

        $randChars = '';
        for ($i=0; $i < $len ; $i++) {
            $randChars .= $chars[mt_rand(0, $charsLen)];
        }

        $this->nonce_str = $randChars;
        return $randChars;

    }

    /**
     * 写日志
     * @param $path
     * @param $data
     */
    public static function logResult($path, $data)
    {

        if (!is_dir(LOGPATH)) {
            mkdir(LOGPATH, 0777, true);
        }

        file_put_contents(LOGPATH.$path, '[时间：'.date('Y-m-d  h:i:i',time()).']，结果：'.$data."\r\n",FILE_APPEND);
    }

    /**
     * [arrayToXml 数组转换成xml]
     * @param  array  $params [description]
     * @return [type]         [description]
     */
    public static function arrayToXml(array $params)
    {
        $xml = "<xml>";

        foreach ($params as $key => $value) {
            if (is_numeric($value)) {
                $xml .= "<{$key}>{$value}</{$key}>";
            } else {
                $xml .= "<{$key}><![CDATA[".$value."]]></{$key}>";
            }
        }

        return $xml.'</xml>';
    }

	/**
	 * XML编码
	 * @param mixed $data 数据
	 * @param string $root 根节点名
	 * @param string $item 数字索引的子节点名
	 * @param string $attr 根节点属性
	 * @param string $id   数字索引子节点key转换的属性名
	 * @param string $encoding 数据编码
	 * @return string
	 */
	public function xml_encode($data, $root = 'xml', $item = 'item', $attr = '', $id = 'id', $encoding = 'utf-8') {
		if (is_array($attr)) {
			$_attr = array();
			foreach ($attr as $key => $value) {
				$_attr[] = "{$key}=\"{$value}\"";
			}
			$attr = implode(' ', $_attr);
		}
		$attr = trim($attr);
		$attr = empty($attr) ? '' : " {$attr}";
		$xml = "<{$root}{$attr}>";
		$xml .= self::data_to_xml($data, $item, $id);
		$xml .= "</{$root}>";
		return $xml;
	}

	/**
	 * GET 请求
	 * @param string $url
	 */
	private function http_get($url)
    {
		$oCurl = curl_init();
		if (stripos($url, "https://") !== FALSE) {
			curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
			curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);
		}
		curl_setopt($oCurl, CURLOPT_URL, $url);
		curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
		$sContent = curl_exec($oCurl);
		$aStatus = curl_getinfo($oCurl);
		curl_close($oCurl);
		if (intval($aStatus["http_code"]) == 200) {
			return $sContent;
		} else {
			return false;
		}
	}

	/**
	 * POST 请求
	 * @param string $url
	 * @param array $param
	 * @return string content
	 */
	public function http_post($url, $param)
    {
		$oCurl = curl_init();
		if (stripos($url, "https://") !== FALSE) {
			curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
			curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);
		}
		if (is_string($param)) {
			$strPOST = $param;
		} else {
			$aPOST = array();
			foreach ($param as $key => $val) {
				$aPOST[] = $key . "=" . urlencode($val);
			}
			$strPOST = join("&", $aPOST);
		}
        //file_put_contents('./mylog.txt',$url."\r\n".$strPOST."\r\n".date('Y-m-d H:i:s')."\r\n==============\r\n",FILE_APPEND);
		curl_setopt($oCurl, CURLOPT_URL, $url);
		curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($oCurl, CURLOPT_POST, true);
		curl_setopt($oCurl, CURLOPT_POSTFIELDS, $strPOST);
		$sContent = curl_exec($oCurl);
		$aStatus = curl_getinfo($oCurl);
		curl_close($oCurl);
		if (intval($aStatus["http_code"]) == 200) {
			return $sContent;
		} else {
			return false;
		}
	}

	/**
	 * 微信api不支持中文转义的json结构
	 * @param array $arr
	 */
	static function json_encode($arr) {
		$parts = array();
		$is_list = false;
		//Find out if the given array is a numerical array
		$keys = array_keys($arr);
		$max_length = count($arr) - 1;
		if (($keys[0] === 0) && ($keys[$max_length] === $max_length)) {//See if the first key is 0 and last key is length - 1
			$is_list = true;
			for ($i = 0; $i < count($keys); $i++) {//See if each key correspondes to its position
				if ($i != $keys[$i]) {//A key fails at position check.
					$is_list = false;
					//It is an associative array.
					break;
				}
			}
		}
		foreach ($arr as $key => $value) {
			if (is_array($value)) {//Custom handling for arrays
				if ($is_list)
					$parts[] = self::json_encode($value);
				/* :RECURSION: */
				else
					$parts[] = '"' . $key . '":' . self::json_encode($value);
				/* :RECURSION: */
			} else {
				$str = '';
				if (!$is_list)
					$str = '"' . $key . '":';
				//Custom handling for multiple data types
				if (is_numeric($value) && $value < 2000000000)
					$str .= $value;
				//Numbers
				elseif ($value === false)
					$str .= 'false';
				//The booleans
				elseif ($value === true)
					$str .= 'true';
				else
					$str .= '"' . addslashes($value) . '"';
				//All other things
				// :TODO: Is there any more datatype we should be in the lookout for? (Object?)
				$parts[] = $str;
			}
		}
		$json = implode(',', $parts);
		if ($is_list)
			return '[' . $json . ']';
		//Return numerical JSON
		return '{' . $json . '}';
		//Return associative JSON

	}

    /**
     *	 * 获取第三方平台令牌（component_access_token）
     * 数据实例：{"component_appid":"appid_value" , "component_appsecret": "appsecret_value",  "component_verify_ticket": "ticket_value"   }
     * @return bool
     */
	public function get_access_token()
    {


        $cache =Cm::$db->one(
            "SELECT component_access_token_expires,component_access_token FROM `scrm_weixin_three_account` WHERE appid='{$this->appid}'"
        );

        $result = $this -> http_post(self::API_URL_PREFIX . self::API_COMPONENT_TOKEN_URL, json_encode($this -> options));
        if ($result) {
			$json = json_decode($result, true);
			if (!$json || !empty($json['errcode'])) {
				$this -> errCode = $json['errcode'];
				$this -> errMsg = $json['errmsg'];
				return false;
			}
			$this -> component_access_token = $json['component_access_token'];
			//写入文件来设置缓存
            if (!$cache) {
                Cm::$db->insert('scrm_weixin_three_account', [
                    'id'=>(new \app\api\core\CreateUuid())->toString(),
                    'component_access_token'=>$this->component_access_token,
                    'appid'=>$this->appid,
                    'component_access_token_expires'=>time()+7100
                ]);
            } else {
                Cm::$db->update('scrm_weixin_three_account', [
                    'component_access_token'=>$this->component_access_token,
                    'component_access_token_expires'=>time()+7100
                ], "appid='{$this->appid}'");
            }
//
			return $this -> component_access_token;
		}
		return false;
	}

    /**
     * 获取预授权码
     * @return bool
     */
	public function get_auth_code() {

        $component_access_token = $this -> getAccessToken();

		$result = $this -> http_post(self::API_URL_PREFIX . self::API_CREATE_PREAUTHCODE_URL . $component_access_token, json_encode(array('component_appid' => $this -> appid)));


		if ($result) {
			$json = json_decode($result, true);
			if (!$json || !empty($json['errcode'])) {
				$this -> errCode = $json['errcode'];
				$this -> errMsg = $json['errmsg'];
				return false;
			}
			return $json['pre_auth_code'];
		}
		return false;
	}

    /**
     * 通过返回授权码换取公众号的授权信息
     * @param $auth_code
     * @param int $companyId
     * @param bool $info
     * @return bool|mixed
     */
	public function get_authorization_info($auth_code, $companyId = 0, $info = false) {

		$component_access_token = $this -> getAccessToken();
		$result = $this -> http_post(self::API_URL_PREFIX . self::API_QUERY_AUTH_URL . $component_access_token, json_encode(array('component_appid' => $this -> appid, 'authorization_code' => $auth_code)));
        if ($result) {
			$json = json_decode($result, true);
			if (!$json || !empty($json['errcode'])) {
				$this -> errCode = $json['errcode'];
				$this -> errMsg = $json['errmsg'];
				return false;
			}

            YII_DEBUG && self::logResult('/wechat-info.log','公众号基本信息：'.$result);

            $json = $json['authorization_info'];

			$data = Cm::$db->one("SELECT id FROM `scrm_weixin_account` WHERE accountappid='{$json['authorizer_appid']}'");

			//基础数据
			$wechat = [
                'status'=>1,
                'authorizer_access_token'=>$json['authorizer_access_token'],
                'authorizer_access_token_time'=>time()+7100,
                'authorizer_refresh_token'=>$json['authorizer_refresh_token'],
            ];

			//权限集合
            $per = [];
            if (isset($json['func_info']) && is_array($json['func_info'])) {
                foreach ($json['func_info'] as $item) {
                    if (isset($item['funcscope_category']['id'])) {
                        array_push($per, $item['funcscope_category']['id']);
                    }
                }

                if (!empty($per)) {
                    sort($per);
                    $wecaht['func_info'] = implode(',', $per);
                }
            }

			if (!$data) {
                $wechat['id'] = (new \app\api\core\CreateUuid())->toString();
			    $wechat['accountappid']=$json['authorizer_appid'];

                Cm::$db->insert('scrm_weixin_account', $wechat);
                $wxId = $wechat['id'] ;
            } else {
                $wxId = $data['id'];

                Cm::$db->update('scrm_weixin_account', $wechat,"accountappid='{$json['authorizer_appid']}'");
            }

            //建立关系：
            $realation = Cm::$db->one("SELECT company_id FROM `scrm_weixin_company_account` WHERE wx_account_id='{$json['authorizer_appid']}' and company_id='{$companyId}'");
            if (!$realation) {
                Cm::$db->insert('scrm_weixin_company_account', [
                    'id'=>(new \app\api\core\CreateUuid())->toString(),
                    'company_id'=>$companyId,
                    'wx_account_id'=>$wxId,
                    'created_at'=>date('Y-m-d H:i:s'),
                ]);
            }
            if ($info) {
			    $this->get_authorizer_info($json['authorizer_appid'], true);
            }
			return $json;
		}
		return false;
	}

    /**
     * 获取授权公众号的authorizer_access_token
     * @param $authorizer_appid
     * @return bool
     */
    public function get_authorizer_access_token($authorizer_appid)
    {

        $cache = Cm::$db->one("SELECT authorizer_access_token,authorizer_access_token_time,authorizer_refresh_token FROM `scrm_weixin_account` WHERE accountappid='{$authorizer_appid}'");

        $authorizer_access_token = false;

        if ($cache) {
            if ((int)$cache['authorizer_access_token_time'] > time()) {
                $authorizer_access_token = $cache['authorizer_access_token'];
            } else {
                $authorizer_refresh_token = $cache['authorizer_refresh_token'];

                $authorizer_access_token = $this -> get_refresh_token($authorizer_appid, $authorizer_refresh_token);
            }
        }
        //读取缓存

        return $authorizer_access_token;
    }

    /**
     * 获取（刷新）授权公众号的令牌
     * 该API用于在授权方令牌（authorizer_access_token）失效时，可用刷新令牌（authorizer_refresh_token）获取新的令牌。
     * @param $authorizer_appid
     * @param $authorizer_refresh_token
     * @return bool
     */
	public function get_refresh_token($authorizer_appid, $authorizer_refresh_token)
    {

	
		$component_access_token = $this -> getAccessToken();
		$result = $this -> http_post(self::API_URL_PREFIX . self::API_AUTHORIZER_TOKEN_URL . $component_access_token, json_encode(array('component_appid' => $this -> appid, 'authorizer_appid' => $authorizer_appid, 'authorizer_refresh_token' => $authorizer_refresh_token)));
		if ($result) {
			$json = json_decode($result, true);
			if (!$json || !empty($json['errcode'])) {
				$this -> errCode = $json['errcode'];
				$this -> errMsg = $json['errmsg'];
				return false;
			}

            $data = Cm::$db->one("SELECT authorizer_access_token,authorizer_access_token_time,authorizer_refresh_token FROM `scrm_weixin_account` WHERE accountappid='{$authorizer_appid}'");

			if (!$data) {
                Cm::$db->insert('scrm_weixin_account', [
                    'id' => (new \app\api\core\CreateUuid())->toString(),
                    'accountappid'=>$json['authorizer_appid'],
                    'authorizer_access_token'=>$json['authorizer_access_token'],
                    'authorizer_access_token_time'=>time()+7100,
                    'authorizer_refresh_token'=>$authorizer_refresh_token,
                ]);
            } else {
                Cm::$db->update('scrm_weixin_account', [
                    'authorizer_access_token'=>$json['authorizer_access_token'],
                    'authorizer_access_token_time'=>time()+7100,
                ], "accountappid='{$authorizer_appid}'");
            }
			$this -> authorizer_access_token = $json['authorizer_access_token'];

			return $this -> authorizer_access_token;
		}
		return false;
	}


    /**
     * 获取授权方的账户信息
     * 该API用于获取授权方的公众号基本信息，包括头像、昵称、帐号类型、认证类型、微信号、原始ID和二维码图片URL。
     * @param $authorizer_appid
     * @param bool $data:是否插入数据：
     * @return bool|mixed
     */
	public function get_authorizer_info($authorizer_appid, $data = false)
    {
		$component_access_token = $this -> getAccessToken();
		$result = $this -> http_post(self::API_URL_PREFIX . self::API_GET_AUTHORIZER_INFO_URL . $component_access_token, json_encode(array('component_appid' => $this -> appid, 'authorizer_appid' => $authorizer_appid)));
		if ($result) {
			$json = json_decode($result, true);
			if (!$json || !empty($json['errcode'])) {
				$this -> errCode = $json['errcode'];
				$this -> errMsg = $json['errmsg'];
				return false;
			}

            YII_DEBUG && self::logResult('/wechat-info.log','公众号具体信息：'.$result);

            $temp = $json['authorizer_info'];
			//写入数据
            if ($data) {
                $data = Cm::$db->one("SELECT id FROM `scrm_weixin_account` WHERE accountappid='{$authorizer_appid}'");
                $wecaht = [
                    'accountname'=>$temp['nick_name'],
                    'accountnumber'=>$temp['user_name'],
                    'user_name'=>$temp['user_name'],
                    'accounttype'=>$temp['service_type_info']['id'],
                    'accountverifytype'=>$temp['verify_type_info']['id'],
                    'qrcode_url'=>$temp['qrcode_url'],
                    'open_store'=>$temp['business_info']['open_store'],
                    'open_scan'=>$temp['business_info']['open_scan'],
                    'open_pay'=>$temp['business_info']['open_pay'],
                    'open_card'=>$temp['business_info']['open_card'],
                    'open_shake'=>$temp['business_info']['open_shake'],
                ];
                //认证信息
                $auth = $json['authorization_info'];
                $wecaht['authorizer_refresh_token'] = $auth['authorizer_refresh_token'];
                //权限api:
                $per = [];
                if (isset($auth['func_info']) && is_array($auth['func_info'])) {
                    foreach ($auth['func_info'] as $item) {
                        if (isset($item['funcscope_category']['id'])) {
                            array_push($per, $item['funcscope_category']['id']);
                        }
                    }

                    if (!empty($per)) {
                        sort($per);
                        $wecaht['func_info'] = implode(',', $per);
                    }
                }
                if (!$data) {
                    $wechat['id'] = (new \app\api\core\CreateUuid())->toString();
                    $wecaht['accountappid'] = $authorizer_appid;
                    Cm::$db->insert('scrm_weixin_account', $wecaht);
                } else {
                    Cm::$db->update('scrm_weixin_account', $wecaht, "accountappid='{$authorizer_appid}'");
                }
            }
			return $json;
		}
		return false;
	}

    /**
     * 获取授权方的选项设置信息
     * @param $authorizer_appid
     * @param $option_name
     * @return bool|mixed
     */
	public function get_authorizer_option($authorizer_appid, $option_name) {

		$component_access_token = $this -> getAccessToken();
		$result = $this -> http_post(self::API_URL_PREFIX . self::API_GET_AUTHORIZER_OPTION_URL . $component_access_token, json_encode(array('component_appid' => $this -> appid, 'authorizer_appid' => $authorizer_appid, 'option_name' => $option_name)));
		if ($result) {
			$json = json_decode($result, true);
			if (!$json || !empty($json['errcode'])) {
				$this -> errCode = $json['errcode'];
				$this -> errMsg = $json['errmsg'];
				return false;
			}

			return $json;
		}
		return false;
	}

    /**
     * 获取授权方的选项设置信息
     * @param $authorizer_appid
     * @param $option_name
     * @param $option_value
     * @return bool|mixed
     */
	public function set_authorizer_option($authorizer_appid, $option_name, $option_value) {

		
		$component_access_token = $this -> getAccessToken();

		$result = $this -> http_post(self::API_URL_PREFIX . self::API_SET_AUTHORIZER_OPTION_URL . $component_access_token, json_encode(array('component_appid' => $this -> appid, 'authorizer_appid' => $authorizer_appid, 'option_name' => $option_name, 'option_value' => $option_value)));
		if ($result) {
			$json = json_decode($result, true);
			if (!$json || !empty($json['errcode'])) {
				$this -> errCode = $json['errcode'];
				$this -> errMsg = $json['errmsg'];
				return false;
			}
			return $json;
		}
		return false;
	}

    /**
     * 获取跳转链接:授权地址
     * @param $callback
     * @param $pre_auth_code
     * @return string
     */
	public function getRedirect($callback, $pre_auth_code) {
		return self::API_REDIRECT . 'component_appid=' . $this -> appid . '&pre_auth_code=' . $pre_auth_code . '&redirect_uri=' . urlencode($callback);
	}

    /**
     * 获取微信第三方平台：component_access_token
     * @return bool
     */
	public function getAccessToken() {

		$cache = //file_read('cache/component_access_token.json');
		//读取缓存
        $cache =Cm::$db->one(
            "SELECT component_access_token, component_access_token_expires FROM `scrm_weixin_three_account` WHERE appid='{$this->appid}'"
        );


		//$cache = json_decode($cache, true);
		if ($cache && $cache['component_access_token_expires'] > time()) {
			$component_access_token = $cache['component_access_token'];
		} else {
			$component_access_token = $this -> get_access_token();
		}
		return $component_access_token;
	}


    /**
     * 批量获取关注用户列表
     * @param $authorizer_appid:微信公总号、appid
     * @param $next_openid：最后一个用户的openid
     * @return bool|mixed
     */
	public function get_user_list ($authorizer_appid, $next_openid='')
    {

        $time = Cm::$db->one("SELECT *FROM `scrm_weixin_account` WHERE accountappid='{$authorizer_appid}'");
        if ($time && $time['sync_customer'] > time()) {
            return true;
        }
        $authorizer_access_token = $this->get_authorizer_access_token($authorizer_appid);

        if (!$authorizer_access_token) {
            return false;
        }

        if($next_openid) {
            $result = $this->http_get(self::API_URL_PREFIX.self::USER_GET_URL.'access_token='.$authorizer_access_token.'&next_openid='.$next_openid);
        } else {
            $result = $this->http_get(self::API_URL_PREFIX.self::USER_GET_URL.'access_token='.$authorizer_access_token);
        }
        if ($result) {
            $json = json_decode($result,true);
            if (isset($json['errcode'])) {
                $this->errCode = $json['errcode'];
                $this->errMsg = $json['errmsg'];
                return false;
            }
            $data = $json['data']['openid'];
            if (!empty($data) && is_array($data)) {
                foreach ($data as $item) {
                    $result = Cm::$db->one("select id, openid from `scrm_weixin_customer` WHERE wx_account_id='{$authorizer_appid}' and openid='{$item}'");
                    if (!$result) {
                        Cm::$db->insert('scrm_weixin_customer', [
                            'id'=> (new \app\api\core\CreateUuid())->toString(),
                            'openid'=>$item,
                            'wx_account_id'=>$authorizer_appid,
                        ]);
                    }
                }
            }
            $next_openid = isset($json['next_openid']) && !empty($json['next_openid']) ? $json['next_openid'] : null;
            //写不写入数据库：
            $total = (int)$json['total'];#粉丝总人数
            $count = (int)$json['count'];#当前粉丝数

            return $json;
        }
        return false;
    }


    /**
     * 批量获取关注用户列表
     * @param string $authorizer_access_token
     * @param string $next_openid：最有一个粉丝的openid
     * @return bool|mixed
     */
	public function getUserList($authorizer_access_token='',$next_openid='')
    {
		
		if($next_openid){
			$result = $this->http_get(self::API_URL_PREFIX.self::USER_GET_URL.'access_token='.$authorizer_access_token.'&next_openid='.$next_openid);
		}else{
			$result = $this->http_get(self::API_URL_PREFIX.self::USER_GET_URL.'access_token='.$authorizer_access_token);
			
		}
		if ($result)
		{
			$json = json_decode($result,true);
			if (isset($json['errcode'])) {
				$this->errCode = $json['errcode'];
				$this->errMsg = $json['errmsg'];
				return false;
			}
			return $json;
		}
		return false;
	}
}
